package com.sc.commons.base.repository;

import lombok.Builder;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * @author
 */
public class JpaQueryUtils<T> {

    private String select;
    private String table;
    private StringBuilder where = new StringBuilder();
    private Map<String, Object> params = new HashMap<>();

    private String sort;
    private Integer page;
    private Integer rows;

    private Class<T> clazz;

    /**
     * builder模式，一次保护，更多吸收。
     * @return
     */
    public static <T> JpaQueryUtils<T> builder(Class<T> clazz) {
        return new JpaQueryUtils<>(clazz);
    }

    private JpaQueryUtils(Class<T> clazz) {
        this.clazz = clazz;
    }

    public JpaQueryUtils<T> build(){
        return this;
    }

    public Class<T> getClazz() {
        return clazz;
    }

    public JpaQueryUtils select(String select) {
        this.select = select;
        return this;
    }

    public JpaQueryUtils from(String table) {
        this.table = table;
        return this;
    }

    public JpaQueryUtils from(Class<?> table) {
        this.table = table.getClass().getName();
        return this;
    }

    /**
     * 等于
     *
     * @param fieldName
     * @param param
     * @return
     */
    public JpaQueryUtils eq(String fieldName, Object param) {
        operatorAnd(fieldName, "=", param);
        return this;
    }


    /**
     * 不等于
     *
     * @param fieldName
     * @param param
     * @return
     */
    public JpaQueryUtils ne(String fieldName, Object param) {
        operatorAnd(fieldName, "!=", param);
        return this;
    }

    public JpaQueryUtils gt(String fieldName, Object param) {
        operatorAnd(fieldName, ">", param);
        return this;
    }

    public JpaQueryUtils ge(String fieldName, Object param) {
        operatorAnd(fieldName, ">=", param);
        return this;
    }


    public JpaQueryUtils lt(String fieldName, Object param) {
        operatorAnd(fieldName, "<", param);
        return this;
    }

    public JpaQueryUtils le(String fieldName, Object param) {
        operatorAnd(fieldName, "<=", param);
        return this;
    }


    /**
     * 全匹配,慎用,不走索引
     *
     * @param fieldName
     * @param param
     * @return
     */
    public JpaQueryUtils like(String fieldName, Object param) {
        operatorAnd(fieldName, "like", "%" + param + "%");
        return this;
    }

    /**
     * 开始模糊匹配
     *
     * @param fieldName
     * @param param
     * @return
     */
    public JpaQueryUtils startLike(String fieldName, Object param) {
        operatorAnd(fieldName, "like", "%" + param);
        return this;
    }

    /**
     * 结束模糊匹配
     *
     * @param fieldName
     * @param param
     * @return
     */
    public JpaQueryUtils endLike(String fieldName, Object param) {
        operatorAnd(fieldName, "like", param + "%");
        return this;
    }

    private JpaQueryUtils operatorAnd(String fieldName, String operator, Object param) {
        // 如果为空，返回
        if (param == null) {
            return this;
        }
        //如果是字符串，并且是空串，也返回
        if (param instanceof String && StringUtils.isEmpty(param)) {
            return this;
        }

        String placeholder = "c_" + UUID.randomUUID().toString().replace("-", "");
        if(StringUtils.hasText(where.toString())){
            where.append(String.format(" and %s %s :%s ", fieldName, operator, placeholder));
        } else {
            where.append(String.format("  %s %s :%s ", fieldName, operator, placeholder));
        }
        params.put(placeholder, param);
        return this;
    }


    public JpaQueryUtils sort(String sort) {
        this.sort = sort;
        return this;
    }

    public JpaQueryUtils page(Integer page, Integer rows){
        this.page = page;
        this.rows = rows;
        return this;
    }

    public String getJpql() {
        StringBuilder sb = new StringBuilder();
        if(StringUtils.hasText(select)){
            sb.append("select " + select);
        }
        if(StringUtils.hasText(table)){
            sb.append(" from " + table);
        }
        if(StringUtils.hasText(where)){
           sb.append(" where " + where);
        }

        if(StringUtils.hasText(sort)){
            sb.append(" order by " + sort);
        }

        return sb.toString();

    }

    public Map<String, Object> getParams() {
        return this.params;
    }


    public Integer getPage() {
        return page;
    }

    public Integer getRows() {
        return rows;
    }
}
